// @flow

// const fs = require("fs");
import fs = require("fs");

// readFileSync calls must be written out long-form for brfs.
/* eslint-disable prefer-template, no-path-concat */

const shaders: {[key: string]: {fragmentSource: string, vertexSource: string}} = {
  prelude: {
    fragmentSource: fs.readFileSync(__dirname + "/../shaders/_prelude.fragment.glsl", "utf8"),
    vertexSource: fs.readFileSync(__dirname + "/../shaders/_prelude.vertex.glsl", "utf8")
  },
  // circle: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/circle.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/circle.vertex.glsl", "utf8")
  // },
  // collisionBox: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/collision_box.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/collision_box.vertex.glsl", "utf8")
  // },
  // debug: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/debug.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/debug.vertex.glsl", "utf8")
  // },
  fill: {
      fragmentSource: fs.readFileSync(__dirname + "/../shaders/fill.fragment.glsl", "utf8"),
      vertexSource: fs.readFileSync(__dirname + "/../shaders/fill.vertex.glsl", "utf8")
  },
  // fillOutline: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/fill_outline.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/fill_outline.vertex.glsl", "utf8")
  // },
  // fillOutlinePattern: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/fill_outline_pattern.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/fill_outline_pattern.vertex.glsl", "utf8")
  // },
  fillPattern: {
      fragmentSource: fs.readFileSync(__dirname + "/../shaders/fill_pattern.fragment.glsl", "utf8"),
      vertexSource: fs.readFileSync(__dirname + "/../shaders/fill_pattern.vertex.glsl", "utf8")
  },
  // fillExtrusion: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/fill_extrusion.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/fill_extrusion.vertex.glsl", "utf8")
  // },
  // fillExtrusionPattern: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/fill_extrusion_pattern.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/fill_extrusion_pattern.vertex.glsl", "utf8")
  // },
  // extrusionTexture: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/extrusion_texture.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/extrusion_texture.vertex.glsl", "utf8")
  // },
  // line: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/line.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/line.vertex.glsl", "utf8")
  // },
  // linePattern: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/line_pattern.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/line_pattern.vertex.glsl", "utf8")
  // },
  // lineSDF: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/line_sdf.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/line_sdf.vertex.glsl", "utf8")
  // },
  // raster: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/raster.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/raster.vertex.glsl", "utf8")
  // },
  // symbolIcon: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/symbol_icon.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/symbol_icon.vertex.glsl", "utf8")
  // },
  // symbolSDF: {
  //     fragmentSource: fs.readFileSync(__dirname + "/../shaders/symbol_sdf.fragment.glsl", "utf8"),
  //     vertexSource: fs.readFileSync(__dirname + "/../shaders/symbol_sdf.vertex.glsl", "utf8")
  // }
};

// Expand #pragmas to #ifdefs.

/* pragma 的格式
* #pragma mapbox: (define|initialize) (lowp|mediump|highp) (float|vec2|vec3|vec4) {name}
*/
const re = /#pragma mapbox: ([\w]+) ([\w]+) ([\w]+) ([\w]+)/g;

for (const programName in shaders) {
    const program = shaders[programName];
    const fragmentPragmas: {[key: string]: boolean} = {};

    program.fragmentSource = program.fragmentSource.replace(re, (match: string, operation: string, precision: string, type: string, name: string) => {
        fragmentPragmas[name] = true;
        if (operation === "define") {
            return `
#ifndef HAS_UNIFORM_u_${name}
varying ${precision} ${type} ${name};
#else
uniform ${precision} ${type} u_${name};
#endif
`;
        } else /* if (operation === "initialize") */ {
            return `
#ifdef HAS_UNIFORM_u_${name}
    ${precision} ${type} ${name} = u_${name};
#endif
`;
        }
    });

    program.vertexSource = program.vertexSource.replace(re, (match: string, operation: string, precision: string, type: string, name: string) => {
        const attrType = type === "float" ? "vec2" : "vec4";
        if (fragmentPragmas[name]) {
            if (operation === "define") {
                return `
#ifndef HAS_UNIFORM_u_${name}
uniform lowp float a_${name}_t;
attribute ${precision} ${attrType} a_${name};
varying ${precision} ${type} ${name};
#else
uniform ${precision} ${type} u_${name};
#endif
`;
            } else /* if (operation === "initialize") */ {
                return `
#ifndef HAS_UNIFORM_u_${name}
    ${name} = unpack_mix_${attrType}(a_${name}, a_${name}_t);
#else
    ${precision} ${type} ${name} = u_${name};
#endif
`;
            }
        } else {
            if (operation === "define") {
                return `
#ifndef HAS_UNIFORM_u_${name}
uniform lowp float a_${name}_t;
attribute ${precision} ${attrType} a_${name};
#else
uniform ${precision} ${type} u_${name};
#endif
`;
            } else /* if (operation === "initialize") */ {
                return `
#ifndef HAS_UNIFORM_u_${name}
    ${precision} ${type} ${name} = unpack_mix_${attrType}(a_${name}, a_${name}_t);
#else
    ${precision} ${type} ${name} = u_${name};
#endif
`;
            }
        }
    });
}

export default shaders;
